/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package Gramatica;

import PL3.Token;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Stack;

/**
 *
 * @author David Fernandez <david@gluem.org>
 */
public class GIC {

    private HashSet<SimboloTerminal> terminales;
    private HashSet<SimboloNoTerminal> noTerminales;
    private Hashtable<SimboloNoTerminal, Produccion> producciones;
    private SimboloNoTerminal inicial;
    public static final SimboloTerminal lambda = new SimboloTerminal('Ï');

    public GIC() {

        terminales = new HashSet<SimboloTerminal>();

    }

    /**
     * @return the terminales
     */
    public HashSet<SimboloTerminal> getTerminales() {
        return terminales;
    }

    /**
     * @param terminales the terminales to set
     */
    public void setTerminales(HashSet<SimboloTerminal> terminales) {
        this.terminales = terminales;
    }

    /**
     * @return the noTerminales
     */
    public HashSet<SimboloNoTerminal> getNoTerminales() {
        return noTerminales;
    }

    /**
     * @param noTerminales the noTerminales to set
     */
    public void setNoTerminales(HashSet<SimboloNoTerminal> noTerminales) {
        this.noTerminales = noTerminales;
    }

    /**
     * @return the producciones
     */
    public Hashtable<SimboloNoTerminal, Produccion> getProducciones() {
        return producciones;
    }

    /**
     * @param producciones the producciones to set
     */
    public void setProducciones(Hashtable<SimboloNoTerminal, Produccion> producciones) {
        this.producciones = producciones;
    }

    /**
     * @return the inicial
     */
    public SimboloNoTerminal getInicial() {
        return inicial;
    }

    /**
     * @param inicial the inicial to set
     */
    public void setInicial(SimboloNoTerminal inicial) {
        this.inicial = inicial;
    }

    @Override
    public String toString() {

        return "Terminales: " + terminales
                + "\nNoTerminales: " + noTerminales
                + "\nInicial: " + inicial
                + "\nProducciones: " + producciones;
    }

    public boolean pertenece(ArrayList<Token> entrada) {


        HashMap<String, HashMap<String, ArrayList<ISimbolo>>> tabla = LL1Factory.generarTablaAnalisisSintactico(this);

        boolean pertenece = true;
        boolean fin = false;

        Stack<ISimbolo> pila = new Stack();
        pila.push(LL1Factory.finDeCadena);
        pila.push(this.getInicial());
        int indiceEntrada = 0;

        while (!pila.isEmpty() && indiceEntrada<entrada.size() && !fin) {

            if (pila.peek().getClass().getName().equals("Gramatica.SimboloTerminal")) {

                Token t = entrada.get(indiceEntrada);
                indiceEntrada++;

                if (pila.peek().equals(t.getValor())) {

                    if (pila.peek().equals(LL1Factory.finDeCadena)) {

                        fin = true;

                    } else {

                        pila.pop();

                    }
                } else {

                    pertenece = false;
                    fin = true;
                }



            } else {

                HashMap<String, ArrayList<ISimbolo>> fila = tabla.get(((SimboloNoTerminal) pila.peek()).getSimbolo());

                

                Token t = entrada.get(indiceEntrada);

                ArrayList<ISimbolo> celda = fila.get(t.getValor().getSimbolo());

                if (fila.containsKey(t.getValor().getSimbolo())) {

                    pila.pop();

                    celda = fila.get((t.getValor()).getSimbolo());

                    if (!celda.get(0).equals(GIC.lambda)) {

                        for (int i = celda.size() - 1; i >= 0; i--) {


                            ISimbolo iSim = celda.get(i);

                            pila.push(iSim);
                        }
                    }
                } else {

                    pertenece = false;
                    fin = true;
                }

            }

        }


        return pertenece;
    }

    
}
